<?php

namespace App\Middleware\Admin;

use App\Constants\ErrorCode;
use App\Utils\MD5Token;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Hyperf\HttpServer\Contract\ResponseInterface as HttpResponse;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Router\Dispatched;
use Hyperf\Contract\ConfigInterface;
use Hyperf\Di\Annotation\Inject;
use App\Model\Administrator;
use Psr\EventDispatcher\EventDispatcherInterface;
class PermissionMiddleware implements MiddlewareInterface
{
    protected ContainerInterface $container;
    protected RequestInterface $request;
    protected HttpResponse $response;
    /**
     * @Inject
     * @var ConfigInterface
     */
    protected ConfigInterface $config;
    #[Inject]
    protected MD5Token $md5Token;
    /**
     * @var Administrator
     */
    protected Administrator $userModel;
    /**
     * @var EventDispatcherInterface
     */
    protected EventDispatcherInterface $eventDispatcher;
    protected string|null $token;
    protected string $scene;
    public function __construct(ContainerInterface $container, HttpResponse $response, RequestInterface $request)
    {
        $this->container = $container;
        $this->response = $response;
        $this->request = $request;
        $this->token = $request->header('X-Token','');
        $this->scene = "admin_token:";
        $this->md5Token = new MD5Token();
        $this->userModel = new Administrator();
        $this->eventDispatcher = $container->get(EventDispatcherInterface::class);//监听事件
    }
    /**
     * Notes:处理请求
     * 2025/7/10
     * @param ServerRequestInterface $request
     * @param RequestHandlerInterface $handler
     * @return ResponseInterface
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        try {
            $white_list_route = $this->config->get('permission.white_list_route', []);
            if (in_array($this->request->getRequestUri(), $white_list_route)) {
                return $handler->handle($request);
            }

            try {
                [$controller, $action] = $this->request->getAttribute(Dispatched::class)->handler->callback;
            } catch (\Exception $exception) {
                $data = [
                    'code' => \App\Constants\ErrorCode::ROUTE_NOT_EXIST,
                    'message' => \App\Constants\ErrorCode::getMessage(\App\Constants\ErrorCode::ROUTE_NOT_EXIST),
                ];
                return $this->response->json($data);
            }

            $controllerArray = explode('\\', $controller);
            $controller = $controllerArray[count($controllerArray) - 1];
            $controllerName = substr($controller, 0, -10);
            $admin = $this->md5Token->verifyToken($this->token);
            $user = $this->userModel->where('id', $admin['id'])->first();
            if (!$user) {
                return $this->response->json([
                    'code' => \App\Constants\ErrorCode::DATA_NOT_EXIST,
                    'message' => \App\Constants\ErrorCode::getMessage(\App\Constants\ErrorCode::DATA_NOT_EXIST),
                    'data' => (object)[]
                ]);
            }
            // 判断当前用户是否有当前请求的权限
            if (! $user->hasPermission($controllerName, $action, $this->request->getMethod())) {
                $data = [
                    'code' => \App\Constants\ErrorCode::PERMISSION_DENIED,
                    'message' => \App\Constants\ErrorCode::getMessage(\App\Constants\ErrorCode::PERMISSION_DENIED),
                ];
                return $this->response->json($data);
            }
            $this->eventDispatcher->dispatch(new \App\Event\ActionLog($this->request, $user, $controllerName, $action));

            return $handler->handle($request);
        }catch (\Exception $e){
            return $this->response->json([
                'code' => $e->getCode(),
                'message' => $e->getMessage(),
                "data"=>(object)[]
            ]);
        }
    }
}